package com.example.mybatis.config;

import com.example.mybatis.util.ConstraintViolationUtils;
import com.example.mybatis.util.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ConstraintViolationException;

/**
 * 全局异常处理（可以参考 {@link org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler}） 由于在处理中
 * MethodArgumentNotValidException 和上面冲突不能继承这个类
 *
 * @author lr
 */
@ControllerAdvice
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {


    @ExceptionHandler({Exception.class})
    public Object handleCommonException(Exception e) {
        log.error(" GlobalException Exception 异常 {}", e.getMessage());
        return R.error();
    }

    /**
     * {@link org.springframework.validation.annotation.Validated} {@link javax.validation.Valid} spring mvc controller中
     * 校验 Bean信息 使用上面两个都可以的，后面跟上一个BindResult，这样非常不方便，统一起来处理
     *
     * @param e
     * @return
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        BindingResult result = e.getBindingResult();
        ObjectError error = result.getAllErrors().get(0);
        String message = error.getDefaultMessage();
        log.debug("GlobalException MethodArgumentNotValidException validator error errorName={},message={} ", error.getObjectName(), error.getDefaultMessage(), e);
        return ConstraintViolationUtils.parseMessageAndCodeFromValidatorError(message);
    }

    /**
     * {@link org.springframework.validation.annotation.Validated}
     * {@link org.springframework.validation.beanvalidation.MethodValidationPostProcessor}
     * 扫描类上含有Validated注解的类，含有校验不通过抛出异常 {@link org.springframework.validation.beanvalidation.MethodValidationInterceptor}
     * 当前类是主要的处理这，可以了解Hibernate Validator的一些用法
     *
     * @param e
     * @return
     */
    @ExceptionHandler({ConstraintViolationException.class})
    public R handleMethodArgumentNotValidException(ConstraintViolationException e) {
        log.debug("validator error ", e);
        return ConstraintViolationUtils.validatorConstraintViolations(e.getConstraintViolations());
    }
}
